#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"
#include <iostream>
#include <string>

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() {
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSeqInst::getValeur() 
{
  int valeur=0;
  for (unsigned int i=0; i<tabInst.size(); i++)
    valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
  for (unsigned int i=0; i<tabInst.size(); i++)
    tabInst[i]->afficher(indentation+1); // on affiche les fils en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
  tabInst.push_back(instruction);
}


// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
  this->variable=variable;
  this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudAffectation::getValeur() {
  int valeur = expression->getValeur(); // on évalue l'expression
  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudAffectation::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Affectation" << endl;
  variable->afficher(indentation+1);   // on affiche variable et expression
  expression->afficher(indentation+1); // en augmentant l'indentation
}


// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur,
                                               Noeud* operandeGauche,
                                               Noeud* operandeDroit) {
  this->operateur=operateur;
  this->operandeGauche=operandeGauche;
  this->operandeDroit=operandeDroit;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudOperateurBinaire::getValeur() { 
  int valeur=0;
  int og=operandeGauche->getValeur();
  int od=operandeDroit->getValeur();
  // Operateurs Binaires
  if      (this->operateur=="+") valeur = og+od; 
  else if (this->operateur=="-") valeur = og-od;
  else if (this->operateur=="*") valeur = og*od; 
 
   // Operateurs Relationnels 
  else if (this->operateur=="==")
  {
      if (og==od) valeur=1;
      else valeur=0;
  }
  else if (this->operateur=="!=")
  {
      if (og!=od) valeur=1;
      else valeur=0;
  }
  else if (this->operateur=="<")
  {
      if (og<od) valeur =1;
      else valeur=0;
  }
  else if (this->operateur=="<=")
   {
      if (og<=od) valeur =1;
      else valeur=0;
  } 
   else if (this->operateur==">")
  {
      if (og>od) valeur =1;
      else valeur=0;
  } 
   else if (this->operateur==">=")
  {
      if (og>=od) valeur =1;
      else valeur=0;
  }
   // Operateurs Booleens 
   else if (this->operateur=="et")
   {
      if (og && od) valeur =1;
      else valeur=0;
  } 
  else if (this->operateur=="ou")
  {
      if (og || od) valeur =1;
      else valeur=0;
  }
  // this->operateur=="/"
  else  
	if (od!=0)
		valeur = og/od;
  	else {
	  	cout << "Erreur pendant l'interpretation : division par zero" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
  return valeur;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudOperateurBinaire::afficher(unsigned short indentation) 
{
  Noeud::afficher(indentation);
  cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
  operandeGauche->afficher(indentation+1);  // on affiche fils gauche et fils droit
  operandeDroit->afficher(indentation+1);   // en augmentant l'indentation
}

// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudInstSi
////////////////////////////////////////////////////////////////////////////////

NoeudInstSi::NoeudInstSi(Noeud* cond, Noeud* seq) : vectCond(), vectSeqInst()
{
     vectCond.push_back(cond);
     vectSeqInst.push_back(seq);
}

////////////////////////////////////////////////////////////////////////////////
void NoeudInstSi::ajoute(Noeud* cond, Noeud* seq) 
{
        vectCond.push_back(cond);
        vectSeqInst.push_back(seq);
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstSi::getValeur()
{
    int i=0;
    while(i<vectCond.size() && vectCond[i]!=NULL && vectCond[i]->getValeur()==0)
    {
        i++;
    }
    
    if (i<vectCond.size()) 
    {
        vectSeqInst[i]->getValeur();
    }
    
    return 0;
}

////////////////////////////////////////////////////////////////////////////////


 void NoeudInstSi::afficher(unsigned short indentation) 
{
    
    Noeud::afficher(indentation);
    int i =0;
    
    cout << "Noeud - Instruction si " << endl;
    while(i<vectCond.size())
    {
    if (i==0)
    {
        cout << "Si :" << endl;
        
        vectCond[i]->afficher(indentation+1);
        vectSeqInst[i]->afficher(indentation+1);        
    }
    else if (i>0 && vectCond[i]!=NULL)
    {
        cout << "Sinon si :" << endl;
        vectCond[i]->afficher(indentation+1);
        vectSeqInst[i]->afficher(indentation+1);         
    }
    else
    {
        cout << "Sinon : " << endl; 
        vectSeqInst[i]->afficher(indentation+1);
    }
    
    i++;
 }
}
  
// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudInstTq
////////////////////////////////////////////////////////////////////////////////
NoeudInstTq::NoeudInstTq(Noeud* expBool, Noeud* seqInst) 
{
  this->expBool=expBool;
  this->seqInst=seqInst;
}
////////////////////////////////////////////////////////////////////////////////

void NoeudInstTq::afficher(unsigned short indentation) 
{
  Noeud::afficher(indentation);
  cout << "Noeud - Instruction tant que " << endl;
  expBool->afficher(indentation+1);  // condition
  cout<<"faire"<<endl;
  seqInst->afficher(indentation+1);   // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstTq::getValeur()
{
    int valeur=0;
    while(expBool->getValeur())
    {
        valeur=seqInst->getValeur();
    }
    return valeur;
}

// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudInstRepeter
////////////////////////////////////////////////////////////////////////////////
NoeudInstRepeter::NoeudInstRepeter(Noeud* expBool, Noeud* seqInst) 
{
  this->expBool=expBool;
  this->seqInst=seqInst;
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstRepeter::afficher(unsigned short indentation) 
{
  Noeud::afficher(indentation);
  cout << "Noeud - Instruction repeter " << endl;
  seqInst->afficher(indentation+1); //instruction
  cout<<"jusqu'à"<<endl;
  expBool->afficher(indentation+1);  // condition

}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstRepeter::getValeur()
{
    int valeur = 0;
    do(valeur=seqInst->getValeur());
            while(expBool->getValeur());
    return valeur;
}

// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudInstPour
////////////////////////////////////////////////////////////////////////////////
NoeudInstPour::NoeudInstPour(Noeud* affect1, Noeud* expBool, Noeud* affect2,Noeud* inst) 
{
  this->affect1=affect1;
  this->expBool=expBool;
  this->affect2=affect2;
  this->inst=inst;
  
}
////////////////////////////////////////////////////////////////////////////////

void NoeudInstPour::afficher(unsigned short indentation) {
    //    <instPour> : pour (<affectation>;<expBool>; <affectation>) faire { <seqInst> }
  Noeud::afficher(indentation);
  cout << "Noeud - pour ( " << endl;
  affect1->afficher(indentation+1); 
  cout<<";";
  expBool->afficher(indentation+1); 
  cout<<";";
  affect2->afficher(indentation+1);
  cout<<") faire";
  inst->afficher(indentation+1);
}


////////////////////////////////////////////////////////////////////////////////
int NoeudInstPour::getValeur()
{
    int valeur = 0;
    affect1->getValeur();
    while(expBool->getValeur())
    {
        valeur=inst->getValeur();
        affect2->getValeur();
    }
    
    return valeur;
}

////////////////////////////////////////////////////////////////////////////////
// NoeudInstLire
////////////////////////////////////////////////////////////////////////////////
 NoeudInstLire::NoeudInstLire(Noeud* var)
{
    this->var=var;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void NoeudInstLire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Lire " << endl;
  var->afficher(indentation+1); //instruction
  
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstLire::getValeur()
{
    cout << var->getValeur() << endl;
    return(1);
}

// -------------------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
// NoeudInstEcrire
////////////////////////////////////////////////////////////////////////////////
NoeudInstEcrire::NoeudInstEcrire(Noeud* ecrire) 
{
  this->ecrire=ecrire;
 
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstEcrire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - ecrire " << endl;
  ecrire->afficher(indentation+1); //instruction
  
}

////////////////////////////////////////////////////////////////////////////////
int NoeudInstEcrire::getValeur()
{
    cout << ecrire->getValeur() << endl;
    return(1);
}

// -------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////////
//// NoeudRelation
//////////////////////////////////////////////////////////////////////////////////
//NoeudRelation::NoeudRelation(Noeud* exp1) :tabSymb(), tabExp()
//{
//  this->exp1=exp1;
//}
//////////////////////////////////////////////////////////////////////////////////
//
//void NoeudRelation::afficher(unsigned short indentation) 
//{
//    //    <instPour> : pour (<affectation>;<expBool>; <affectation>) faire { <seqInst> }
//  Noeud::afficher(indentation);
//  cout<<"afficher relation"<<endl;
//  exp1->afficher(indentation+1);
//  
//  for (unsigned int i=0; i<tabExp.size(); i=i+2)
//  {
//      cout<<"est comparé avec"<<tabSymb[i];
//      
//      cout<< "à "<<endl;
//      tabExp[i]->afficher(indentation+1); // on affiche la seq d'instruction qui va avec la condition
//  }
//  
//}
//////////////////////////////////////////////////////////////////////////////////
//void NoeudRelation::ajouteRel(Symbole symb, Noeud* exp2)
//{
//    tabSymb.push_back(symb);
//    tabExp.push_back(exp2);
//}
//////////////////////////////////////////////////////////////////////////////////
//int NoeudRelation::getValeur()
//{
//    if(tabSymb[0]!=NULL){return 1;}
//    int i=0;
//    int valeur=1;
//    while(i<tabExp.size() && tabSymb[i]!=NULL && valeur!=0)
//    {
////       valeur est mis a vra(1), si l'expression est fausse, valeur est mis a faux (0) et on sort de la boucle.
//        if((tabSymb[i]=="<") && !((tabExp[i]->getValeur())<(tabExp[i+1]->getValeur()))
//                ||tabSymb[i]=="<=" && !((tabExp[i]->getValeur())<=(tabExp[i+1]->getValeur()))
//                ||tabSymb[i]==">" && !((tabExp[i]->getValeur())>(tabExp[i+1]->getValeur()))
//                ||tabSymb[i]==">=" && !((tabExp[i]->getValeur())>=(tabExp[i+1]->getValeur()))
//                ||tabSymb[i]=="==" && !((tabExp[i]->getValeur())==(tabExp[i+1]->getValeur()))
//          )
//        {valeur=0;}
//
//        i++;
//        
//    }
//    
//    return valeur;
//}


// -------------------------------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////////
//// NoeudExpBool
//////////////////////////////////////////////////////////////////////////////////
//NoeudExpBool::NoeudExpBool(Noeud* termeBool1) :tabTermeBool()
//{
//    
//    tabTermeBool.push_back(termeBool1);
//
//}
//////////////////////////////////////////////////////////////////////////////////
//
//void NoeudExpBool::afficher(unsigned short indentation) 
//{
//    //    <instPour> : pour (<affectation>;<expBool>; <affectation>) faire { <seqInst> }
//  Noeud::afficher(indentation);
//  int i=0;
//cout<<"afficher expBool"<<endl;
//        
//  tabTermeBool[i]->afficher(indentation+1); 
//  i++;
//  
//  for (i; i<tabTermeBool.size(); i++)
//  {
//      cout<<" ou ";
//      tabTermeBool[i]->afficher(indentation+1); 
//      
//  }
//  
//}
//////////////////////////////////////////////////////////////////////////////////
//void NoeudExpBool::ajouteExpBool( Noeud* termeBool2)
//{
//    
//    tabTermeBool.push_back(termeBool2);
//}
//////////////////////////////////////////////////////////////////////////////////
//
//int NoeudExpBool::getValeur() {
////   <expBool> ::= <termeBool> { <opOu> <termeBool> }
//    
//    int i=0;
//    bool termebool=tabTermeBool[i]->getValeur();
//    i++;
//    int resultat=0;
//    bool termeboolbis;
//    
//    for(; i<tabTermeBool.size(); i++)
//  {
//        termeboolbis=tabTermeBool[i]->getValeur();
//        
//        if (termeboolbis || termebool || resultat){
//        resultat=1;
//        }
//  }
//
//    return resultat;
//    
//    
//
//}
//////////////////////////////////////////////////////////////////////////////////
//// NoeudTermeBool
//////////////////////////////////////////////////////////////////////////////////
//NoeudTermeBool::NoeudTermeBool(Noeud* relation1) :tabRelation()
//{
//    tabRelation.push_back(relation1); 
//}
//////////////////////////////////////////////////////////////////////////////////
//void NoeudTermeBool::ajouteTermeBool(Noeud* relation2){
//    
//    tabRelation.push_back(relation2);
//    
//}
//////////////////////////////////////////////////////////////////////////////////
//
//void NoeudTermeBool::afficher(unsigned short indentation) {
//       //   <temrmeBool>::=<relation> {<opEt> <relation>}  
//    cout<<"afficher termeBool"<<endl;
//  Noeud::afficher(indentation);
//
//  tabRelation[0]->afficher(indentation+1);
//  
//  for (unsigned int i=1; i<tabRelation.size(); i++)
//  {
//      cout<<"et";
//      tabRelation[i]->afficher(indentation+1); 
//      
//  }
//}
//////////////////////////////////////////////////////////////////////////////////
//
//int NoeudTermeBool::getValeur() {
//       //   <termeBool>::=<relation> {<opEt> <relation>} 
//    
//    int resultat=1;
//    int relation;
//    
//    for(unsigned int i=0; i<tabRelation.size(); i++)
//  {
//        
//        relation=tabRelation[i]->getValeur();
//        resultat=(relation && resultat);
//  }
//    if(resultat==0 || resultat==1)
//    {
//    return resultat;
//    }
//    else{cout << "Erreur sur la valeur du booléen (termeBool)" << endl;
//	  	exit(0); // plus tard on levera une exception
//  	}
//    
//}
